package com.canaan.common.encrypt;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;

import java.nio.charset.Charset;
import java.util.Map.Entry;
import java.util.SortedMap;

/**
 * 签名工具类
 *
 * @author du.tang
 * @Version 1.0.0
 */
public class SignUtils {
    /**
     * sign
     */
    public static final String SIGN_KEY = "sign";
    public static final int INT = 4;
    /**
     * 截取块大小
     */
    private static final int BLOCK_LEN = 4;
    /**
     * 与或常量
     */
    private static final int OX_FF = 0xFF;
    /**
     * 1bit
     */
    private static final int BIT = 8;

    /**
     * 计算签名串
     *
     * @param signMap 参数map
     * @return 签名
     */
    public static String getSignStr(SortedMap<String, String> signMap) {
        StringBuilder sb = new StringBuilder();
        for (Entry<String, String> e : signMap.entrySet()) {
            String key = e.getKey();
            if (StringUtils.isNotEmpty(signMap.get(key)) && !key.equals(SIGN_KEY)) {
                String value = e.getValue();
                sb.append(key).append("=").append(value).append(";");
            }
        }
        return sb.substring(0, sb.length() - 1);
    }

    /**
     * md5签名
     *
     * @param targetStr 明文
     * @return 密文
     */
    public static String doMd5Sign(String targetStr) {
        byte[] md5Result = DigestUtils.md5(targetStr.getBytes(Charset.defaultCharset()));
        if (md5Result.length != BLOCK_LEN * INT) {
            throw new IllegalArgumentException("MD5加密结果字节数组错误");
        }
        int first = Math.abs(bytesToInt(md5Result, 0));
        int second = Math.abs(bytesToInt(md5Result, BLOCK_LEN));
        int third = Math.abs(bytesToInt(md5Result, BLOCK_LEN * 2));
        int fourth = Math.abs(bytesToInt(md5Result, BLOCK_LEN * 3));
        return Integer.toString(first) + second + third + fourth;
    }

    /**
     * 高位前，低位后，字节数组转INT
     *
     * @param src    源字符
     * @param offset 偏移量
     * @return 结果
     */
    private static int bytesToInt(byte[] src, int offset) {
        int value;
        value = ((src[offset] & OX_FF) << 3 * BIT) | ((src[offset + 1] & OX_FF) << 2 * BIT) | ((src[offset + 2] & OX_FF) << BIT) | (src[offset + 3] & OX_FF);
        return value;
    }
}
